package com.seer.srd.qingdao

import com.fasterxml.jackson.module.kotlin.jacksonTypeRef
import com.seer.srd.BusinessError
import com.seer.srd.eventlog.EventLogLevel
import com.seer.srd.eventlog.SystemEvent
import com.seer.srd.eventlog.recordSystemEventLog
import com.seer.srd.http.Handlers
import com.seer.srd.http.ReqMeta
import com.seer.srd.qingdao.CustomDataService.agvStopAudio
import com.seer.srd.qingdao.EnableBoardCheck.toLabel
import com.seer.srd.qingdao.CustomDataService.maxNumOfGallery
import com.seer.srd.storesite.StoreSiteService
import com.seer.srd.util.mapper
import io.javalin.http.Context
import org.slf4j.LoggerFactory

object CustomHandler {
    private val logger = LoggerFactory.getLogger(CustomHandler::class.java)

    fun registerCustomHttpHandlers() {
        val operator = Handlers("task-by-operator")
        operator.post("enable-board-check", ::handleEnableBoardCheck, ReqMeta(auth = false))
        operator.post("agv-stop-audio", ::handleAgvStopAudio, ReqMeta(auth = false))
        // 设置物料暂存区运输任务触发数量
        operator.post("update-wt-take-size", ::handleUpdateWTTakeSize, ReqMeta(auth = false))
        operator.post("freeze-storeSite", ::handleFreezeStoreSite, ReqMeta(auth = false))

        val ext = Handlers("ext")
        ext.get("user-config", ::handleListConfig, ReqMeta(auth = false, test = false))
        ext.post("check-password", ::handleCheck, ReqMeta(auth = false, test = false))
        // 停止创建物料转运任务
        ext.post("stop-create-mat-transfer/{newValue}", ::handleStopCreateMatTransferTask, ReqMeta(auth = false))
        // 停止创建物料入库任务
        ext.post("stop-create-mat-in-store/{newValue}", ::handleStopCreateMatInStoreTask, ReqMeta(auth = false))

        //测试接口
        val root = Handlers("")
        root.post("test/rv_check_status", ::handleTestRoboView, ReqMeta(auth = false, test = true))
    }

    private fun handleEnableBoardCheck(ctx: Context) {
        val req = ctx.bodyAsClass(PdaReqBody::class.java)
        val paramsObj = mapper.convertValue(req.params, jacksonTypeRef<EnableBoardCheckReq>())
        val enable = paramsObj.enable
        if (enable == EnableBoardCheck.Unknown) throw BusinessError("请选择操作")
        val old = CustomDataService.getCustomData().enableBoardCheck
        logger.debug("enable board check from ${toLabel(old)} to ${toLabel(enable)}")
        CustomDataService.enableBoardCheck(enable)
    }

    private fun handleAgvStopAudio(ctx: Context) {
        logger.debug("agv stop audio from ${ctx.req.remoteAddr}")

        val req = ctx.bodyAsClass(PdaReqBody::class.java)
        val paramsObj = mapper.convertValue(req.params, jacksonTypeRef<StopAudioReq>())
        val siteId = paramsObj.siteId
        if (siteId.isBlank() || siteId == "-") throw BusinessError("请先选择机器人当前所在的库位！")
        if (agvStopAudio[siteId] == null)
            throw BusinessError("库位【$siteId】上没有正在执行任务，且处于报警状态的机器人！")
        agvStopAudio(siteId)
    }

    private fun handleUpdateWTTakeSize(ctx: Context) {
        val req = ctx.bodyAsClass(PdaReqBody::class.java)
        val paramsObj = mapper.convertValue(req.params, jacksonTypeRef<UpdateGallerySettingsReq>()).check()
        CustomDataService.setWTTakeSize(paramsObj.gallery, paramsObj.maxNum, ctx.req.remoteAddr)
    }

    private fun handleFreezeStoreSite(ctx: Context) {
        val req = ctx.bodyAsClass(PdaReqBody::class.java)
        val paramsObj = mapper.convertValue(req.params, jacksonTypeRef<FreezeStoreSiteSettingsReq>()).check()
        CustomDataService.setStoreSiteStatus(paramsObj.gallery,paramsObj.index,paramsObj.disabled, ctx.req.remoteAddr)
    }

    // 从配置文件输出工位及其密码
    private fun handleListConfig(ctx: Context) {
        ctx.json(CUSTOM_CONFIG.userConfig)
    }

    // 用于手持端登录密码校验
    private fun handleCheck(ctx: Context) {
        val newWt = ctx.queryParam("newWt") ?: throw BusinessError("岗位不能为空")
        val newWs = ctx.queryParam("newWs") ?: throw BusinessError("工位不能为空")
        val oldWt = ctx.queryParam("oldWt")
        val oldWs = ctx.queryParam("oldWs")
        val pwd = ctx.queryParam("pwd")
        if (pwd.isNullOrBlank()) throw BusinessError("密码不能为空")
        logger.debug("old work type=$oldWt, old work station=$oldWs, new work type=$newWt, new work station=$newWs")
        val findWs = CUSTOM_CONFIG.userConfig.filter { it.workStation == newWs }
        if (findWs.isEmpty()) {
            if (pwd.trim() != newWs.trim()) throw BusinessError("密码输入错误")
        } else {
            if (findWs.size > 1) throw BusinessError("工位信息配置异常，请检查服务器配置")
            if (pwd.trim() != findWs[0].pwd.trim()) throw BusinessError("密码输入错误")
        }
    }

    private fun handleStopCreateMatTransferTask(ctx: Context) {
        val newValue = ctx.pathParam("newValue").toBoolean()
        val old = CustomDataService.getCustomData().stopCreateMatTransferTask
        logger.debug("更新缓物料缓存区允许放置数量：from $old to $newValue by ${ctx.req.remoteAddr}")
        CustomDataService.stopCreateMatTransferTask(newValue)
    }

    private fun handleStopCreateMatInStoreTask(ctx: Context) {
        val newValue = ctx.pathParam("newValue").toBoolean()
        val old = CustomDataService.getCustomData().stopCreateMatInStoreTask
        logger.debug("更新缓物料缓存区允许放置数量：from $old to $newValue by ${ctx.req.remoteAddr}")
        CustomDataService.stopCreateMatInStoreTask(newValue)
    }

    /**
     * 以下用于模拟roboView请求响应
     */
    private fun handleTestRoboView(ctx: Context) {
        //    用于postman 测试
        //    val req = mapper.readTree(ctx.body())
        //    val data = JavalinJson.fromJson(req.toString(),DashboardCheckResponseTest::class.java)
        //    println(data)
        //    ctx.json(mapOf("code" to "200", "message" to "successful"))
    }

    // 用于组件测试
    fun testRoboView(req: String): DashboardCheckResponseTest {
        println(req)
        return DashboardCheckResponseTest()
    }

    fun checkBoardCheckSiteId(init: Boolean = false): String {
        if (CUSTOM_CONFIG.boardCheckSiteId.isNotBlank()) return CUSTOM_CONFIG.boardCheckSiteId
        val errorMessage = "看板核对库位不能为空，请检查配置文件"
        if (init) {
            recordSystemEventLog("RobotTask", EventLogLevel.Error, SystemEvent.Extra, errorMessage)
            return ""
        } else throw BusinessError(errorMessage)
    }
}

data class EnableBoardCheckReq(
    val enable: Int = -1
)

data class DashboardCheckResponseTest(
    var name: String = "rv_check_status",
    var status: List<ResponseResultTest> = arrayListOf(ResponseResultTest())
)

data class ResponseResultTest(
    var layers: Int = 3,
    //这里给的数据决定测试时，看板核对的结果，具体逻辑见组件 qingdao:requestDashboardCheck
    var bin_result: List<BinResultTest> = arrayListOf(
        BinResultTest(1, false),
        BinResultTest(2, true),
        BinResultTest(3, true)
    )
)

data class BinResultTest(
    var layer: Int,
    var board: Boolean
)

data class PdaReqBody(
    val menuId: String,
    val workStation: String,
    val workType: String,
    val params: Any
)

data class StopAudioReq(
    val siteId: String
)

data class UpdateGallerySettingsReq(
    val gallery: String,
    val maxNum: Int
) {
    fun check(): UpdateGallerySettingsReq {
        if (gallery.isBlank()) throw BusinessError("请选择需要设置的巷道！")
        if (gallery == "-") throw BusinessError("请选择需要设置的巷道!")
        if (maxNum == 0) throw BusinessError("请选择数值（1-8）!")
        val fixedMaxNum = if (maxNum > maxNumOfGallery) maxNumOfGallery else maxNum
        return this.copy(gallery = gallery, maxNum = fixedMaxNum)
    }
}

data class FreezeStoreSiteSettingsReq(
        val gallery: String,
        val index: Int,
        val disabled: Boolean
) {
    fun check(): FreezeStoreSiteSettingsReq {
        if (gallery.isBlank()) throw BusinessError("请选择行/列!")
        if (gallery == "-") throw BusinessError("请选择行/列!")
        if (index == 0) throw BusinessError("请选择行/列!")
        val site = StoreSiteService.getExistedStoreSiteById("$gallery-$index")
        if (site.disabled == disabled){
            throw BusinessError("该库位【$gallery-$index】已被冻结/解冻，请检查库位状态！")
        }
        return this.copy( gallery = gallery,index = index, disabled = disabled)
    }
}

enum class Area {
    WT, // 物料暂存区 TEMP       每个巷道的库位数量都是 8 个
    WB  // 物料缓存区 BUFFER     每个巷道的库位数量都是 6 个
}